package com.hundsun.cprs.yyt.service.account.service.impl;

import com.hundsun.cprs.yyt.common.base.BaseService;
import com.hundsun.cprs.yyt.common.enums.EnumBusinessCode;
import com.hundsun.cprs.yyt.common.exception.ServiceCodeException;
import com.hundsun.cprs.yyt.common.redis.RedisDistributedLock;
import com.hundsun.cprs.yyt.service.account.domain.query.AccountQuotaLogQuery;
import com.hundsun.cprs.yyt.service.account.enums.EnumQuotaTransType;
import com.hundsun.cprs.yyt.service.account.service.AccountQuotaLogService;
import com.hundsun.cprs.yyt.service.account.service.AccountQuoteLimitService;
import com.hundsun.cprs.yyt.service.common.Constants;
import com.hundsun.cprs.yyt.util.DateUtil;
import com.hundsun.cprs.yyt.util.DoubleUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundZSetOperations;
import org.springframework.data.redis.core.DefaultTypedTuple;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.text.MessageFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

@Service
public class AccountQuoteLimitServiceImpl extends BaseService implements AccountQuoteLimitService {

    private static final String YYT_QUOTE_USE_LOCK = Constants.YYT_QUOTE_USE_LOCK;//用户配额消费记录锁
    private static final String YYT_QUOTE_USE_COUNT = Constants.YYT_QUOTE_USE_COUNT;//用户配额消费计数器

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    @Autowired
    private RedisDistributedLock redisLock;
    @Autowired
    private AccountQuotaLogService accountQuotaLogService;

    @Override
    public void addUserQuoteToCache(Long userId, Long quoteAmount) {
        String createLockKey = MessageFormat.format(YYT_QUOTE_USE_LOCK, userId);
        String cacheKey = YYT_QUOTE_USE_COUNT;
        try{
            //获取创建锁,竞争则等待
            if(redisLock.lock(createLockKey)){
                BoundZSetOperations<String,Object> zSetOper = redisTemplate.boundZSetOps(cacheKey);
                if (redisTemplate.hasKey(cacheKey)){
                    Double count = zSetOper.score(userId);
                    if (count != null){
                        count = DoubleUtil.add(count,quoteAmount);
                        zSetOper.add(userId,count);
                    }else{
                        initUserQuoteCache(cacheKey,userId,quoteAmount);
                        //zSetOper.add(userId,quoteAmount);
                    }
                }else{
                    //不存在则初始化用户配额消费计数器
                    initUserQuoteCache(cacheKey,userId,quoteAmount);
                    //zSetOper.add(userId,quoteAmount);
                    //设置缓存的过期时间为当天
                    //zSetOper.expireAt(DateUtil.getEndOfDay(new Date()));
                }
            }else{
                throw new ServiceCodeException(EnumBusinessCode.BUSINESS_1000.getErrorNo(), "无法获取用户配额消费记录锁[" + userId + "]");
            }
        }finally{
            redisLock.releaseLock(createLockKey);
        }
    }

    @Override
    public Long getUserUsedQuoteCurrent(Long userId) {
        String cacheKey = YYT_QUOTE_USE_COUNT;
        Long value = 0L;
        BoundZSetOperations<String,Object> zSetOper = redisTemplate.boundZSetOps(cacheKey);
        if (redisTemplate.hasKey(cacheKey)){
            Double count = zSetOper.score(userId);
            if (count != null){
                value = count.longValue();
            }
        }else{
            value = initUserQuoteCache(cacheKey,userId,0L);
        }
        return value;
    }

    //初始化用户当日消费配额缓存
    protected Long initUserQuoteCache(String cacheKey,Long userId,Long quoteAmount){
        String initCacheLockKey = new StringBuilder(cacheKey).append("_LOCK").toString();
        try {
            Long amount = 0L;
            if (redisLock.lock(initCacheLockKey)) {
                BoundZSetOperations<String,Object> zSetOper = redisTemplate.boundZSetOps(cacheKey);
                //db取到用户当日已经消费配额
                AccountQuotaLogQuery quotaLogQuery = new AccountQuotaLogQuery();
                quotaLogQuery.setUserId(userId);
                quotaLogQuery.setTransType(EnumQuotaTransType.TRANS_0101.getCode());
                quotaLogQuery.setStartDate(DateUtil.getBeginOfDay(new Date()));
                quotaLogQuery.setEndDate(DateUtil.getEndOfDay(new Date()));
                amount = accountQuotaLogService.getDaliyUserUsedQuoteAmount(quotaLogQuery);
                amount = amount + quoteAmount;
                zSetOper.add(userId,amount);
                //设置缓存的过期时间为当天
                zSetOper.expireAt(DateUtil.getEndOfDay(new Date()));
            }
            return amount;
        } finally {
            redisLock.releaseLock(initCacheLockKey);
        }
    }
}
